package com.hifar.utils;

import com.hifar.fw.utils.exception.BusinessException;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;

public class Camera2Utils {

    private static Logger logger = LoggerFactory.getLogger(Camera2Utils.class);

    // 接口的实例，通过接口实例调用外部dll/so的函数
    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;

    // 用户登录返回句柄
    static int lUserID;
    int iErr = 0;

    /**
     * @param m_sDeviceIP 设备ip地址
     */
    public static Map<String, Object> Login_V40(String m_sDeviceIP, String userName, String port, String pwd) {
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (initSuc != true) {
            throw new BusinessException("SDK未初始化");
        }
        FileUtils.getTempDirectory();
        // 打印SDK日志
        String tempDirectoryPath = FileUtils.getTempDirectoryPath();
        String logDirPath = tempDirectoryPath + File.separator + "SDKLog";
        hCNetSDK.NET_DVR_SetLogToFile(3, logDirPath, false);
        HashMap<String, Object> resMap = new HashMap<>();
        // 获取设备登录信息
//        String m_sUsername = SysCommonUtil.getSysConfigValueByKey(request, "camera_login_username");
//        String camera_port = SysCommonUtil.getSysConfigValueByKey(request, "camera_port");
        short wPort = Short.parseShort(port);
//        String m_sPassword = SysCommonUtil.getSysConfigValueByKey(request, "camera_login_pwd");

        // 设备登录信息
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();

        // 设备信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
        m_strLoginInfo.wPort = wPort;
        m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        System.arraycopy(userName.getBytes(), 0, m_strLoginInfo.sUserName, 0, userName.length());
        m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
        System.arraycopy(pwd.getBytes(), 0, m_strLoginInfo.sPassword, 0, pwd.length());
        // 是否异步登录：false- 否，true- 是
        m_strLoginInfo.bUseAsynLogin = false;
        // write()调用后数据才写入到内存中
        m_strLoginInfo.write();

        lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            throw new BusinessException("登录失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
        } else {
            logger.info("登录成功");
            // read()后，结构体中才有对应的数据
            m_strDeviceInfo.read();
            resMap.put("lUserID", lUserID);
            resMap.put("deviceInfo", m_strDeviceInfo);

        }
        return resMap;
    }


    /**
     * 截图
     *
     * @param userId
     */
    public static byte[] captureJPEGPicture(Integer userId, int iChannelNum) {
        byte[] bytes = null;
        BufferedOutputStream bufferedOutputStream = null;
        FileOutputStream fileOutputStream = null;

        //图片质量
        HCNetSDK.NET_DVR_JPEGPARA jpeg = new HCNetSDK.NET_DVR_JPEGPARA();
        //设置图片分辨率
        jpeg.wPicSize = 2;
        //设置图片质量
        jpeg.wPicQuality = 2;
        IntByReference a = new IntByReference();
        //设置图片大小
        Pointer p = new Memory(3840 * 2160);
        // 抓图到内存，单帧数据捕获并保存成JPEG存放在指定的内存空间中
        boolean is2 = hCNetSDK.NET_DVR_CaptureJPEGPicture_NEW(userId, iChannelNum, jpeg, p, 3840 * 2160, a);
        System.out.println(hCNetSDK.NET_DVR_GetLastError());
        if (is2) {
            logger.info("抓拍成功，已存到内存");
        } else {
            throw new BusinessException("抓拍失败，错误码为" + hCNetSDK.NET_DVR_GetLastError());
        }

        bytes = p.getByteArray(0, a.getValue());
        return bytes;
    }

    /**
     * 截图并且保存图片
     *
     * @param m_sDeviceIP
     * @param fileName
     * @param tempPath
     * @param userName   用户名
     * @param port  端口
     * @param pwd   密码
     */
    public static void captureAndSave(String m_sDeviceIP, String fileName, String tempPath, String userName, String port, String pwd) {
        // 登录设备
        Map<String, Object> loginMap = Login_V40(m_sDeviceIP, userName, port, pwd);
        HCNetSDK.NET_DVR_DEVICEINFO_V40 deviceInfo = (HCNetSDK.NET_DVR_DEVICEINFO_V40) loginMap.get("deviceInfo");
        int startChan = deviceInfo.struDeviceV30.byStartChan;
        int lUserID = (int) loginMap.get("lUserID");
        byte[] jpegPicture = captureJPEGPicture(lUserID, startChan);
        CameraUtils.saveDataToFile(jpegPicture, jpegPicture.length, fileName, tempPath);
        //退出登录
        hCNetSDK.NET_DVR_Logout(lUserID);
        //释放SDK资源
        hCNetSDK.NET_DVR_Cleanup();
    }


    /**
     * 开始录制视频
     *
     * @param filePath
     * @param lUserID
     */
    public static int startRecord(String filePath, String fileName, int lUserID) {
        HCNetSDK.NET_DVR_CLIENTINFO m_strClientInfo = new HCNetSDK.NET_DVR_CLIENTINFO();
        m_strClientInfo.lChannel = 1;
        m_strClientInfo.lLinkMode = 0;
        m_strClientInfo.hPlayWnd = null;
        //用当前时间戳来命名视频名字
        long time = System.currentTimeMillis();
        // 创建文件目录
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }


//        fileName = String.format("%s\\%s.MP4", filePath,fileName);
        fileName = filePath + File.separator + fileName + ".mp4";

        int lRealHandle = hCNetSDK.NET_DVR_RealPlay_V30(lUserID, m_strClientInfo, null, null, true);
        //如果失败了，在重新来一次
        if (lRealHandle == -1) {
            lRealHandle = hCNetSDK.NET_DVR_RealPlay_V30(lUserID, m_strClientInfo, null, null, true);
            logger.error("预览失败，正在重试，错误代码为===" + hCNetSDK.NET_DVR_GetLastError());
        }
        //录像
        boolean mark = false;
        mark = hCNetSDK.NET_DVR_SaveRealData(lRealHandle, fileName);
        if (!mark) {
            logger.error("录像失败,，错误代码为===" + hCNetSDK.NET_DVR_GetLastError() + "-----");
        }
        return lRealHandle;
    }


    /**
     * 结束录制，释放资源
     *
     * @param lRealHandle
     */
    public static void finishRecord(int lRealHandle) {
        // 结束录制
        hCNetSDK.NET_DVR_StopSaveRealData(lRealHandle);
        //退出登录
        hCNetSDK.NET_DVR_Logout(lUserID);
        //释放SDK资源
        hCNetSDK.NET_DVR_Cleanup();
    }

}
